package top.huxy.boot.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import top.huxy.boot.BlogApiApplication;
import top.huxy.boot.config.RedisKeyConfig;
import top.huxy.boot.mapper.ExceptionLogMapper;
import top.huxy.boot.model.dto.Pager;
import top.huxy.boot.model.dto.Query;
import top.huxy.boot.model.entity.ExceptionLog;
import top.huxy.boot.service.ExceptionLogService;
import top.huxy.boot.util.ExceptionUtils;
import top.huxy.boot.util.StringUtils;
import top.huxy.boot.util.obj.Pagination;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Classname ExceptionLogServiceImpl
 * @Description ExceptionLogServiceImpl
 * @Date 2021/9/19 15:02
 * @Created by huxy
 */
@Service
@Slf4j
public class ExceptionLogServiceImpl implements ExceptionLogService {

    @Autowired
    ExceptionLogMapper exceptionLogMapper;

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    public static ExceptionLogServiceImpl getInstance() {
        return BlogApiApplication.app.getBean(ExceptionLogServiceImpl.class);
    }

    @Override
    public void saveExceptionLog2Redis(ExceptionLog exceptionLog) {
        //保存到redis
        redisTemplate.opsForList().rightPush(RedisKeyConfig.TEMP_EXCEPTION_LOG, exceptionLog);
    }

    @Override
    public int getExceptionLogCount() {
        return exceptionLogMapper.getExceptionLogCount();
    }

    @Override
    public List<ExceptionLog> getExceptionLogList(Pagination pagination) {
        return exceptionLogMapper.getExceptionLogList(pagination.getLeftIndex(), pagination.getRightIndex());
    }

    @Override
    public PageInfo<ExceptionLog> getExceptionLogList(Pager pager, Query query) {
        query
                .allowKey("requestId", false)
                .replaceValue("requestId", StringUtils::stringMax32)

                .allowKey("startTime", false)
                .replaceValue("startTime", Long::parseLong)

                .allowKey("endTime", false)
                .replaceValue("endTime", Long::parseLong)

                .allowKey("r", false)
                .replaceValue("r", str -> {
                    if ("y".equals(str) || "n".equals(str)) return str;
                    return null;
                })

                .allowKey("exceptionNames", false)
                .replaceValue("exceptionNames", str -> new ArrayList<>(Arrays.asList(str.split(","))))
        ;

        PageHelper.startPage(pager.getPage(), pager.getPageSize(), "create_time desc");
        return new PageInfo<>(exceptionLogMapper.getExceptionLogListByFilter(query.getQueryMap()));
    }

    @Override
    public String saveRedisExceptionLog2DB() {
        Long size = redisTemplate.opsForList().size(RedisKeyConfig.TEMP_EXCEPTION_LOG);
        if (size == null || size == 0) return "未保存任何数据，因为size=" + size;

        StringBuilder sb = new StringBuilder();
        int errCount = 0;
        long length = size;
        long time_start = System.currentTimeMillis();

        for (int i = 0; i < length; i++) {
            Object o = redisTemplate.opsForList().leftPop(RedisKeyConfig.TEMP_EXCEPTION_LOG);
            if (o instanceof ExceptionLog) {
                ExceptionLog obj = (ExceptionLog) o;
                try {
                    exceptionLogMapper.saveLog(obj);
                } catch (Exception e) {
                    ExceptionUtils.logError(e);
                    errCount++;
                }
            } else {
                String msg = "不是预期的值o instanceof ExceptionLog is false";
                ExceptionUtils.logError(new RuntimeException(msg));
                sb.append(msg).append("\n");
                errCount++;
            }
            //锁续命
            redisTemplate.expire(RedisKeyConfig.LOCK_SAVE_EXCEPTION_LOG, 30L, TimeUnit.SECONDS);
        }
        long time_end = System.currentTimeMillis();
        sb.append("执行消耗")
                .append(time_end - time_start)
                .append("毫秒。")
                .append("错误次数")
                .append(errCount)
                .append("。执行总数")
                .append(size);
        return sb.toString();
    }

    @Override
    public List<String> getExceptionLogExceptNames() {
        return exceptionLogMapper.getExceptionLogExceptNames();
    }
}
